package cn.qzbook.redisData;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.connection.RedisListCommands;
import org.springframework.data.redis.core.RedisTemplate;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author zc
 * @Date 2020/11/9 下午11:18
 */
public class RedisList {

    public static void main(String[] args) {
//        byte[] bytes = "list".getBytes(Charset.forName("UTF-8"));
//        for (byte b : bytes){
//            System.out.println((char) b);
//        }
        testList();

        System.out.println("==========");

        testBList();
    }


    /**
     * RedisTemplate对list的常用操作
     * */
    public static void testList(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");

        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);

        try {
            redisTemplate.delete("list");

            //从左侧插入一个节点
            redisTemplate.opsForList().leftPush("list","node3");

            List<String> nodeList = new ArrayList<>();

            for (int i = 2; i >= 1 ; i--) {
                nodeList.add("node"+i);
            }
            //从左侧插入一个list集合
            redisTemplate.opsForList().leftPushAll("list",nodeList);
            //从右侧插入一个节点
            redisTemplate.opsForList().rightPush("list","node4");

            //获取下表为0 的节点
            String index = (String) redisTemplate.opsForList().index("list", 0);
            System.out.println(index);
            //获取链表长度
            Long size = redisTemplate.opsForList().size("list");
            System.out.println(size);

            //从左边弹出一个节点
            String leftPop = (String) redisTemplate.opsForList().leftPop("list");
            //从右边弹出一个节点
            String rightPop = (String) redisTemplate.opsForList().rightPop("list");

            //注意，需要使用底层命令才能使用linsert命令
            //在node2节点前，添加一个before_node节点
            redisTemplate.getConnectionFactory().getConnection().lInsert("list".getBytes(Charset.forName("utf-8")),
                    RedisListCommands.Position.BEFORE,
                    "node2".getBytes(Charset.forName("utf-8")),
                    "before_node".getBytes(Charset.forName("utf-8")));

            //在node2节点后，添加一个before_node节点
            redisTemplate.getConnectionFactory().getConnection().lInsert("list".getBytes(Charset.forName("utf-8")),
                    RedisListCommands.Position.AFTER,
                    "node2".getBytes(Charset.forName("utf-8")),
                    "after_node".getBytes(Charset.forName("utf-8")));

            //判断list是否存在，如果存在则从左边插入head节点
            redisTemplate.opsForList().leftPushIfPresent("list","head");
            //判断list是否存在，如果存在则从右边插入end节点
            redisTemplate.opsForList().leftPushIfPresent("list","end");

            //从左到右，或者从下标从 0 到 10 的节点元素
            List<String> valueList = redisTemplate.opsForList().range("list",0,10);

            //在链表左边插入三个职位node的节点
            nodeList.clear();
            for (int i = 1; i <=3 ; i++){
                nodeList.add("node");
            }

            //从左到右删除至多三个node节点
            redisTemplate.opsForList().remove("list",3,"node");

            //给链表下表为0的节点设置新值
            redisTemplate.opsForList().set("list",0,"new_head_value");

        }catch (Exception e){
            e.printStackTrace();
        }

        //打印链表数据
        printList(redisTemplate,"list");

    }



    /**
     * Spring对Redis的阻塞命令操作
     * */
    public static void testBList(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");

        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);

        redisTemplate.delete("list1");
        redisTemplate.delete("list2");

        //初始化链表
        List<String> nodeList = new ArrayList<>();

        for (int i = 1; i <= 5; i++){
            nodeList.add("node"+i);
        }

        redisTemplate.opsForList().leftPushAll("list1",nodeList);
        //Spring使用参数超时时间作为阻塞命令区分，等价于blpop命令，并且可以设置时间参数
        redisTemplate.opsForList().leftPop("list1",1, TimeUnit.SECONDS);

        //spring使用超时时间作为阻塞命令区分，等价于brpop命令，并且可以设置时间参数
        redisTemplate.opsForList().rightPop("list1",1,TimeUnit.SECONDS);

        nodeList.clear();
        //初始化链表二
        for (int i = 1; i <= 3; i++){
            nodeList.add("data"+i);
        }

        redisTemplate.opsForList().leftPushAll("list2",nodeList);

        //相当于rpoplpush，弹出list1最右边的节点，插入到list2的最左边
        redisTemplate.opsForList().rightPopAndLeftPush("list1","list2");
        //相当于brpoplpush，注意，在spring中使用超时参数区分
        redisTemplate.opsForList().rightPopAndLeftPush("list1","list2",1,TimeUnit.SECONDS);

        //打印链表数据
        printList(redisTemplate,"list1");

        System.out.println("=========");

        printList(redisTemplate,"list2");

    }



    public static void printList(RedisTemplate redisTemplate,String key){
        //链表长度
        Long size = redisTemplate.opsForList().size(key);
        //获取整个链表的值
        List<String> range = redisTemplate.opsForList().range(key, 0, size);

        for (String v : range){
            System.out.println(v);
        }

    }

}
